package com.tjhzzx.ibmsSupervisor.alarm;

import com.tjhzzx.ibmsSupervisor.alarm.entities.AlarmClassItem;
import com.tjhzzx.ibmsSupervisor.alarm.entities.AlarmItem;
import com.tjhzzx.ibmsSupervisor.alarm.entities.RealAlarmMessage;
import com.tjhzzx.ibmsSupervisor.util.TimeUtil;
import com.tridium.alarm.BConsoleRecipient;

import javax.baja.alarm.*;
import javax.baja.collection.BITable;
import javax.baja.naming.BOrd;
import javax.baja.naming.SlotPath;
import javax.baja.security.BPermissions;
import javax.baja.security.PermissionException;
import javax.baja.sys.BAbsTime;
import javax.baja.sys.Cursor;
import javax.baja.sys.Sys;
import javax.baja.user.BUser;
import javax.baja.user.BUserService;
import javax.baja.util.BUuid;
import java.io.IOException;
import java.util.*;
import java.util.logging.Logger;

public class AlarmManager {
    private static final Logger LOGGER = Logger.getLogger(AlarmManager.class.getName());
    private static RealAlarmMessage realAlarmMsg = null;
    private static Object mapMutex = new Object();
    private static Map<String, List<AlarmItem>> alarmMap = new HashMap();

    public static List<AlarmClassItem> getAlarmClassesOnConsoleRecipient() {
        List<AlarmClassItem> alarmClassItems = new ArrayList<>();
        BAlarmService alarmSev = (BAlarmService) Sys.getService(BAlarmService.TYPE);
        BConsoleRecipient[] consoleRecipients = alarmSev.getChildren(BConsoleRecipient.class);
        if ((null == consoleRecipients) || (consoleRecipients.length == 0)) {
            return alarmClassItems;
        }
        BConsoleRecipient consoleRecipient = consoleRecipients[0];
        String[] alarmClassArr = consoleRecipient.getSubscribedAlarmClasses();
//        LOGGER.log(Level.SEVERE, "getAlarmClassesOnConsoleRecipient search: " + alarmClassArr);
        if ((alarmClassArr == null) || (alarmClassArr.length == 0)) {
            return alarmClassItems;
        }
        for (int i = 0; i < alarmClassArr.length; i++) {
//            LOGGER.log(Level.SEVERE, "getAlarmClassesOnConsoleRecipient b: " + alarmClassArr[i]);
            AlarmClassItem alarmClassItem = new AlarmClassItem();
            alarmClassItem.name = SlotPath.unescape(alarmClassArr[i]);
//            LOGGER.log(Level.SEVERE, "getAlarmClassesOnConsoleRecipient a: " + alarmClassItem.name);
            alarmClassItems.add(alarmClassItem);
        }
        return alarmClassItems;
    }

    private static void checkPermission(RealAlarmMessage request) {
        BUserService localBUserService = (BUserService) Sys.getService(BUserService.TYPE);
        BUser localBUser = localBUserService.getAdmin();

//        LOGGER.log(Level.SEVERE, "localBUser b: " + localBUser);
        if (!localBUser.getEnabled()) {
            BUser[] arrayOfBUser = localBUserService.getChildren(BUser.class);
            for (int i = 0; i < arrayOfBUser.length; i++) {
                if ((arrayOfBUser[i].getEnabled()) && (arrayOfBUser[i].getPermissions().isSuperUser())) {
                    localBUser = arrayOfBUser[i];
//                    LOGGER.log(Level.SEVERE, "localBUser f: " + localBUser);
                    break;
                }
            }
        }
//        LOGGER.log(Level.SEVERE, "localBUser a: " + localBUser);
        BAlarmService localBAlarmService = (BAlarmService) Sys.getService(BAlarmService.TYPE);
//        LOGGER.log(Level.SEVERE, "localBAlarmService: " + localBAlarmService);
        for (String clazz : request.alarmClass) {
            try {
                localBUser.check(localBAlarmService.lookupAlarmClass(clazz), BPermissions.operatorRead);
            } catch (PermissionException localPermissionException) {
//                LOGGER.log(Level.SEVERE, "PermissionException: " + localPermissionException);
                localPermissionException.printStackTrace();
            }
        }
    }

    private static String getRealAlarmBql(RealAlarmMessage request) {
        StringBuffer localStringBuffer1 = new StringBuffer("alarm:|bql:select * from openAlarms ");
        int i = 0;
        StringBuffer localStringBuffer2 = new StringBuffer();
        for (String alarmClass : request.alarmClass) {
            if (i > 0) {
                localStringBuffer2.append(" or ");
            } else {
                localStringBuffer2.append("(");
            }
            i++;
            localStringBuffer2.append("alarmClass = '" + SlotPath.escape(SlotPath.escape(alarmClass)) + '\'');
        }
        if (i > 0) {
            localStringBuffer2.append(")");
        }
        if (localStringBuffer2.length() > 0) {
            localStringBuffer1.append(" where ");
            localStringBuffer1.append(localStringBuffer2.toString());
        } else {
            localStringBuffer1.append(" where alarmClass = 'null'");
        }
        localStringBuffer1.append(" and ((ackState='acked' and sourceState='offnormal') or ackState='unacked')");
        localStringBuffer1.append(" order by timestamp desc");
        return localStringBuffer1.toString();
    }

    private static Map<String, List<AlarmItem>> getRealAlarmDataMap(RealAlarmMessage request) {
//        LOGGER.log(Level.SEVERE, "getRealAlarmDataMap: " + request);
        String bql = getRealAlarmBql(request);
//        LOGGER.log(Level.SEVERE, "getRealAlarmDataMap getRealAlarmBql: " + bql);
        checkPermission(request);
        BITable tb = (BITable) BOrd.make(bql).get();
//        LOGGER.log(Level.SEVERE, "getRealAlarmDataMap BITable: " + tb);
        Map<String, List<AlarmItem>> map = new HashMap<>();
        Cursor c = tb.cursor();getRealAlarmDataMap:
        while (c.next()) {
            BAlarmRecord record = (BAlarmRecord) c.get();
            String src = record.getSource().toString();
            AlarmItem item = new AlarmItem();
            item.ord = src;
            item.uuid = record.getUuid().toString();
            item.timestamp = TimeUtil.getFormatTimeString(record.getTimestamp(), "YY-MM-DD hh:mm:ss");
            item.ackTime = record.getUser() + "/" + TimeUtil.getFormatTimeString(record.getAckTime(), "YY-MM-DD hh:mm:ss");
            item.sourceState = record.getSourceState().getTag();
            item.ackState = record.getAckState().getTag();
            item.source = record.getAlarmData().get("sourceName").toString();
            item.alarmClass = SlotPath.unescape(record.getAlarmClass());
            item.msgText = record.getAlarmData().get("msgText").toString();
//            LOGGER.log(Level.SEVERE, "getRealAlarmDataMap item: " + item);
            if (!map.containsKey(src)) {
                if (record.getAckState().getTag().equals("acked")) {
                    item.ackNum = 1;
                } else {
                    item.unAckNum = 1;
                }
                List<AlarmItem> alarmItems = new LinkedList<>();
//                LOGGER.log(Level.SEVERE, "getRealAlarmDataMap containsKey: " + item);
                alarmItems.add(item);
                map.put(src, alarmItems);
            } else {
                List<AlarmItem> alarmItems = map.get(src);
                AlarmItem first = alarmItems.get(0);
                if (record.getAckState().getTag().equals("acked")) {
                    first.ackNum++;
                } else {
                    first.unAckNum++;
                }
//                LOGGER.log(Level.SEVERE, "getRealAlarmDataMap first: " + item);
                alarmItems.add(item);
            }
        }
        return map;
    }

    public static List<AlarmItem> getRealAlarmData(RealAlarmMessage request) {
        List<AlarmItem> alarmItems = new ArrayList<>();
        realAlarmMsg = request;
//        LOGGER.log(Level.SEVERE, "getRealAlarmData: " + request);
        Map<String, List<AlarmItem>> map = getRealAlarmDataMap(request);
        synchronized (mapMutex) {
            alarmMap = map;
            if (alarmMap.size() > 0) {
                for (String src : alarmMap.keySet()) {
                    List<AlarmItem> alarmItemList = alarmMap.get(src);
                    alarmItems.add(alarmItemList.get(0));
                }
            }
        }
        return alarmItems;
    }

    public static synchronized List<AlarmItem> getRealAlarmDetail(String ord) {
        List<AlarmItem> items = new ArrayList<>();
        Map<String, List<AlarmItem>> map = getRealAlarmDataMap(realAlarmMsg);
        if (map.containsKey(ord)) {
            List<AlarmItem> alarmItems = map.get(ord);
            if (alarmItems != null && alarmItems.size() > 0) {
                items.addAll(alarmItems);
            }
        }
        return items;
    }

    public static boolean ackEachAlarm(String user, String[] uuids, boolean force) {
        BAlarmService s = (BAlarmService) Sys.getService(BAlarmService.TYPE);
        for (int i = 0; i < uuids.length; i++) {
            String uuid = uuids[i];
            try {
                BAlarmDatabase db = s.getAlarmDb();
                BAlarmRecord record = (BAlarmRecord) db.getConnection(null).getRecord(BUuid.make(uuid.toString())).newCopy();
                if (record.getAckRequired()) {
                    record.ackAlarm(user);
                    record.setAckState(BAckState.acked);
                    record.setAckRequired(false);
                    record.setAckTime(BAbsTime.now());
                }
                if (force) {
                    record.setSourceState(BSourceState.normal);
                }
                s.getAlarmDb().getDbConnection(null).update(record);
                s.doAckAlarm(record);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    public static boolean ackAllAlarm(String user, String[] ords, boolean force) {
        synchronized (mapMutex) {
            for (int i = 0; i < ords.length; i++) {
                List<AlarmItem> alarmItems = alarmMap.get(ords[i]);
                if(alarmItems != null) {
                    for(AlarmItem item: alarmItems) {
                        ackEachAlarm(user, new String[]{item.uuid}, force);
                    }
                }
            }
        }
        return true;
    }
}
